package com.joyer.web.execption;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.joyer.core.valid.InterfaceUtil;
import com.joyer.enums.ErrorPromptEnum;
import com.joyer.exception.BusinessException;
import com.joyer.utils.MessageUtil;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Map;

/**
 * @author wzy
 */
@ControllerAdvice
public class DefaultExceptionHandler {
    private final Logger logger = LoggerFactory.getLogger(getClass());
    @Autowired
    private MessageUtil messageUtil;
    @Autowired
    private InterfaceUtil interfaceUtil;
    @ExceptionHandler(value = Exception.class)
    public ModelAndView defaultErrorHandler(HttpServletRequest request,HttpServletResponse response, Exception e){
        ModelAndView mv = new ModelAndView();
        String errMsg,errCode;

        if (e instanceof BusinessException) {
            errMsg = e.getMessage();
            errCode = ((BusinessException) e).getErrorCode();
        } else {
            String msgKey = e.getClass().getName() + ".msg";
            String codeKey = e.getClass().getName() + ".code";
            errMsg = messageUtil.getMessage(msgKey, null);
            errCode = messageUtil.getMessage(codeKey, null);
            if (StringUtils.isEmpty(errCode)) {
                errCode = ErrorPromptEnum.ERROR_SERVER.getCode();
            }
            if (StringUtils.isEmpty(errMsg)) {
                //未定义的异常
                logger.error( getErrorInfoFromException(e));
                if (e instanceof NullPointerException) {
                    errMsg = ErrorPromptEnum.ERROR_SERVER.getName();
                } else {
                    errMsg = ErrorPromptEnum.ERROR_SERVER.getName();
                }
            }
        }
        Map<String, Object> map = interfaceUtil.getReturnMap4Error(errCode, errMsg);
        mv.addObject("status", map.get("status"));
        mv.addObject("errcode", map.get("errcode"));
        mv.addObject("errmsg", map.get("errmsg"));
        logger.debug("exception name is " + e.getClass().getSimpleName() + ", and excepiton message :" + JSON.toJSONString(map));
        if (isAjaxRequest(request) || isFakeAjax(request)) {
            try {
                JSONObject json = (JSONObject) JSONObject.toJSON(mv.getModel());
                mv.addObject("json", json.toJSONString());
                mv.setViewName("error/ajax");
                response.setCharacterEncoding("UTF-8");
                response.setContentType("application/json;charset=utf-8");
                response.getWriter().print(JSONObject.toJSONString(map));
                response.getWriter().flush();
                response.getWriter().close();
            } catch (IOException e1) {
                mv.addObject("exception", JSON.toJSONString(map));
                mv.setViewName("error/exception");
            }

        } else {
            mv.addObject("exception", JSON.toJSONString(map));
            mv.setViewName("error/exception");
        }
        return mv;
    }


    private boolean isFakeAjax(HttpServletRequest request){
        return StringUtils.equals("true", request.getParameter("isAjax"));
    }

    private boolean isAjaxRequest(HttpServletRequest request) {
        String accept = request.getHeader("accept");
        String requestWith = request.getHeader("X-Requested-With");
        boolean isAjax = (StringUtils.isNotBlank(accept) && accept.contains("application/json"))
                || (StringUtils.isNotBlank(requestWith) && requestWith.contains("XMLHttpRequest"))
                || request.getRequestURL().toString().endsWith(".json");
        logger.debug("isAjax : " + isAjax);
        return isAjax;
    }

    public static String getErrorInfoFromException(Exception e) {
        try {
            StringWriter sw = new StringWriter();
            PrintWriter pw = new PrintWriter(sw);
            e.printStackTrace(pw);
            return sw.toString() + "\n";
        } catch (Exception e2) {
            return "bad getErrorInfoFromException";
        }
    }
}
